<?php
/**
 * User: chaofml
 * Desc: 简单的触发器模型。比如时间触发，比如条件检测。
 * Date: 2020年8月14日
 * Time: 14:16 周五
 */

namespace chaofml\crontab;
// include 'CrontabService.php';

class EventService
{
    /**
     * 1、任务列表，二维数组，如 [['* * * * *','\service\EventService::test',[1,2]]]; （任务写时，任务更新需要手动重启）
     * 2、或者二维数组对应的文件名称。（支持任务更新）
     * 3、TODO 从数据库中加载或者解析
     */
    protected $tasks = [];
    protected $cron = null;

    public function __construct(){
        $this->cron = new CrontabService();
    }

    /**  
    * 运行一次全部任务。
    * @return 
    */ 
    public function run(){
        $c = $this->cron;
        $tasks = $this->getTasks();
        foreach($tasks as $task){
            list($time,$func,$args) = $task;
            $c->setTime($time);
            if($c->isStart()){
                $t0 = microtime(true);
                //TODO 增加分布式锁
                call_user_func_array($func,$args);
                $t1 = microtime(true);
            }
        }
    }
    

    /**
     * loop 循环，每次只执行一次。默认sleep一次。
     * TODO 有可能执行任务时间过长，比如超过了60秒，导致，下一次的任务没有执行。所以，有可能要补上次的任务。
     * 但是，如果某项任务执行，就会超时，再执行还会时间。
     */
    public function loop(){
        //循环之前，先检查任务是否有错误。
        if($tasks = $this->checkTasks()){
            throw new \Exception('Task Wrong:'.join(';',$tasks));
        }

        while(true){
            //增加异常捕获的代码，避免程序意外终止
            try{
                $this->run();
            } catch(\Exception $e){
                echo $e->getMessage();
            }
            sleep(mt_rand(1,4));  //模拟任务执行 时长
            $sleep = 60 - (int)date('s');
            sleep($sleep);
        }
    }
    /**
     * 设置任务。
     * @param tasks 数组或者文件路径
     */
    public function load($tasks){
        $this->tasks = $tasks;
        return $this;
    }

    /**
     * 设置执行的任务，暂时用不上
     */
    public function getTasks(){
        if(is_array($this->tasks)){
            return $this->tasks;
        }
        
        if(is_string($this->tasks)){
            $tasks = require $this->tasks;
            return $tasks;
        }
        throw new \Exception('获取任务错误');
    }

    /**
     * 检查任务，是否可调用。避免用户填错。
     */
    public function checkTasks(){
        $result = [];
        $tasks = $this->getTasks();
        foreach($tasks as $task){
            list($time,$func,$args) = $task;
            if(!is_callable($func)){
                $result[]=$func;
            }
        }
        return $result;
    }

    public static function test($a,$b){
        //函数调用测试。
        // $tmp = '\service\EventService::test';
        // $a = 'suchuanchao';
        // $b = "\r\n";
        // $tmp($a,$b);
        // call_user_func_array($tmp,[$a,$b]);
        // call_user_func($tmp,$a,$b);
        echo 'hello world1234321'.$a.$b;
    }
}

// class Demo{
//     public static function demo(){
//         $time = date('H:i:s');
//         echo "{$time}run demo\n";
//     }
//     public static function time(){
//         $time = date('H:i:s');
//         echo "now $time \r\n";
//     }
// }

// $tasks =  [
//     // ['*/1 * * * *','Demo',[]]
//     ['*/3 13 * * *','\service\Demo::demo',[]],
//     ['* * * * *','\service\Demo::time',[]],
// ];
// $tasks = 'config.php';
// $event = new EventService();
// $event->load($tasks);
// $event->loop();